import { Injectable, Logger } from '@nestjs/common'
import { ConfigService } from '@nestjs/config'
import IORedis from 'ioredis'

@Injectable()
export class NewRedisService {
  private readonly client: IORedis
  private readonly logger = new Logger(NewRedisService.name)

  constructor(private configService: ConfigService) {
    const options = {
      host: this.configService.get('REDIS_HOST', '127.0.0.1'),
      port: this.configService.get('REDIS_PORT', 6379),
      password: this.configService.get('REDIS_PASSWORD'),
      db: this.configService.get('REDIS_DB', 0),
    }

    this.client = new IORedis(options)

    this.client.on('error', (err: Error) => {
      this.logger.error(`Redis连接错误: ${err.message}`)
    })

    this.client.on('connect', () => {
      this.logger.log('Redis连接成功')
    })

    this.client.on('ready', () => {
      this.logger.log('Redis已准备好')
    })

    this.client.on('reconnecting', (delay: number) => {
      this.logger.log(`Redis正在重连，延迟: ${delay}ms`)
    })

    this.client.on('end', () => {
      this.logger.log('Redis连接已关闭')
    })
  }

  async set(key: string, value: any, ttl?: number): Promise<void> {
    const val = typeof value === 'string' ? value : JSON.stringify(value)
    if (ttl) {
      await this.client.setex(key, ttl, val)
    } else {
      await this.client.set(key, val)
    }
  }

  async get<T>(key: string): Promise<T | null> {
    const value = await this.client.get(key)
    if (!value) return null

    try {
      return JSON.parse(value) as T
    } catch {
      return value as T
    }
  }

  async del(key: string): Promise<void> {
    await this.client.del(key)
  }

  async expire(key: string, seconds: number): Promise<void> {
    await this.client.expire(key, seconds)
  }

  async ttl(key: string): Promise<number> {
    return await this.client.ttl(key)
  }

  async exists(key: string): Promise<boolean> {
    return (await this.client.exists(key)) === 1
  }

  async close(): Promise<void> {
    await this.client.quit()
    this.logger.log('Redis连接已关闭')
  }

  async ping(): Promise<string> {
    return await this.client.ping()
  }

  async incr(key: string): Promise<number> {
    return await this.client.incr(key)
  }
}
